{
    "cells": [
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "# PlotControls adjust how a ***design*** is transformed into a 'plot' ***result***\n",
                "\n",
                "***designs*** are transformed into a 'plot' according to some default settings which can be overwritten with a PlotControls object with the following attributes (all demonstrated in this notebook):\n",
                "\n",
                "- `color_type` - options: 'random_blue', 'z_gradient', 'print_sequence', 'print_sequence_fluctuating', 'manual'\n",
                "- `zoom` - recommended range 0.1 - 10\n",
                "- `hide_annotations` - True/False\n",
                "- `hide_travel` - True/False\n",
                "- `hide_axes` - True/False\n",
                "- `neat_for_publishing` - True/False (square format for consistent png creation)\n",
                "- `raw_data` - True/False (output data instead of creating a plot)\n",
                "- `style` - options: 'tube'/'line' - preview 3D real-printed-volume lines or simple lines with non-representative widths\n",
                "    - if `style == 'tube'`:\n",
                "        - `tube_type` - options: 'flow'/'cylinders' - adjust how the plot transitions from line to line\n",
                "        - `tube_sides` - sides of the prisms created for the 3D real-printed-volume lines\n",
                "        - `initialization_data` - define initial width/height of 3D lines with dictionary: {'extrusion_width': value, 'extrusion_height': value}\n",
                "    - if `style == 'line'`:\n",
                "        - `line_width` - recommended range 0.1 - 10\n",
                "    \n",
                "custom plots can be created with the raw data as demonstrated below\n",
                "\n",
                "<*this document is a jupyter notebook - if they're new to you, check out how they work:\n",
                "[link](https://www.google.com/search?q=ipynb+tutorial),\n",
                "[link](https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb),\n",
                "[link](https://colab.research.google.com/)*>\n",
                "\n",
                "*run all cells in this notebook in order (keep pressing shift+enter)*"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "import fullcontrol as fc\n",
                "\n",
                "# this demo design is used for most of the plots in this notebook\n",
                "centre_point = fc.Point(x=50, y=50, z=0)\n",
                "steps = fc.helixZ(centre_point, 20, 15, 0, 30, 0.15, 30*64)\n",
                "steps.append(fc.Extruder(on=False))\n",
                "steps.append(fc.PlotAnnotation(label='extruder off'))\n",
                "steps.append(fc.Point(x=50, y=50, z=0))\n",
                "steps.append(fc.Extruder(on=True))\n",
                "steps.append(fc.PlotAnnotation(label='extruder on'))\n",
                "steps.append(fc.Point(z=5))\n",
                "steps.append(fc.PlotAnnotation(label='finish'))\n",
                "steps.append(fc.PlotAnnotation(point=steps[0], label='start'))\n"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### default plot style\n",
                "\n",
                "lines are shown as 3D lines, where width and height are defined by the extrusion width and height set in initialization data or through ExtrusionGeometry objects in the ***design*** - if unset, default values are width 0.4 and height 0.2"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "fc.transform(steps, 'plot')"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### change color and hide axes / annotations / travel"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "plot_controls = fc.PlotControls(line_width=4, color_type='print_sequence', hide_axes=True, hide_annotations=True, hide_travel=True)\n",
                "fc.transform(steps, 'plot', plot_controls)"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### 'neat_for_publishing' and 'zoom'\n",
                "\n",
                "create a square plot for consistent generation of images for publication with neat_for_publishing=True\n",
                "\n",
                "hover the mouse over the plot and click the camera button (\"Download plot and png\")\n",
                "\n",
                "'zoom' is used to set the initaial zoom level of the plot"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "fc.transform(steps, 'plot', fc.PlotControls(neat_for_publishing=True, zoom=0.6))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### change line size\n",
                "\n",
                "extrusion width and height are controlled in the ***design*** with ExtrusionGeometry objects, as discussed in the State Objects notebook\n",
                "\n",
                "these objects are automatically evaluated - they dictate the widths and heights of lines in the plot\n",
                "\n",
                "the plot can be initated with specific widths and heights by including an 'initialization_data' dictionary in PlotControls (first example below)\n",
                "\n",
                "the specified width and height remain throughout the plot unless the design includes ExtrusionGeometry objects (second example below)\n",
                "\n",
                "if no intitialization data is provided, default values are used: 0.4 wide x 0.2 high"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "plot_controls = fc.PlotControls(initialization_data={'extrusion_width': 0.1, 'extrusion_height': 0.1})\n",
                "fc.transform(steps, 'plot', plot_controls)"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### 'tube_type'\n",
                "\n",
                "set to 'flow' to get smooth transitions between linear segments of the path - this leads to much neater visuals for curves and allows gradual transitions when extrusion width is changed\n",
                "\n",
                "set to 'cylinders' to get a more strict preview of widths defined in the ***design*** - each tube has a contant width according to the designed width"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "varying_width_steps = []\n",
                "varying_width_steps.append(fc.Point(x=0, y=5, z=0.1)) # start point (width defaults to 0.4)\n",
                "varying_width_steps.append(fc.ExtrusionGeometry(width=0.6, height=0.4))\n",
                "varying_width_steps.append(fc.Point(y=0)) # print to this point with width 0.6\n",
                "varying_width_steps.append(fc.ExtrusionGeometry(width=1))\n",
                "varying_width_steps.append(fc.Point(x=5)) # print to this point with width 1\n",
                "varying_width_steps.append(fc.ExtrusionGeometry(width=1.5))\n",
                "varying_width_steps.append(fc.Point(y=5)) # print to this point with width 1.5\n",
                "fc.transform(varying_width_steps + [fc.PlotAnnotation(label='tube_type=\"flow\" (view from above to see clearly)')], 'plot', fc.PlotControls(color_type='print_sequence', tube_type=\"flow\")) # default tube_type=\"flow\"\n",
                "fc.transform(varying_width_steps + [fc.PlotAnnotation(label='tube_type=\"cylinders\" (view from above to see clearly)')], 'plot', fc.PlotControls(color_type='print_sequence', tube_type=\"cylinders\"))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### manual colors\n",
                "\n",
                "set color_type='manual' and assign [r, g, b] colors to points for manual colors\n",
                "\n",
                "any points without the attribute 'color' defined will inherit the color of the previous point\n",
                "\n",
                "colors automatically transition over the length of a line between points with different colors"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "colored_steps = []\n",
                "colored_steps.append(fc.Point(x=0, y=0, z=0.2, color=[1, 0, 0]))\n",
                "colored_steps.append(fc.Point(x=40, y=4, color=[1, 0.8, 0]))\n",
                "colored_steps.append(fc.Point(x=0, y=8))\n",
                "fc.transform(colored_steps, 'plot', fc.PlotControls(color_type='manual'))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### 'tube_sides'\n",
                "\n",
                "extuded lines are plotted as 6-sided hexagonal prisms by default, but the number of sides can be change"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "steps_line = [fc.Point(x=0, y=0, z=0.1), fc.Point(y=1), fc.Point(y=2)]\n",
                "fc.transform(steps_line + [fc.PlotAnnotation(label='8-sided tube', point=steps_line[0])], 'plot', fc.PlotControls(color_type='print_sequence', style=\"tube\", tube_sides=8))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### plot_style (line)\n",
                "\n",
                "as opposed to plotting the path as 3D lines with real volumes representing the width and height of extruded lines, it is possible to create a simple line plot\n",
                "\n",
                "zooming in and out of a line plot does not change the line size and it does not represent the width or height of printed lines\n",
                "\n",
                "the width of the line can be controlled with the 'line_width' attribute\n",
                "\n",
                "however, this type of plot has the advantage that it is less computationally demanding, which may be important for larger models\n",
                "\n",
                "also, this plot is useful for design since the mouse cursor can be used to identify coordinates of points directly on the print path (nozzle position) as opposed to identiying points on the surface of the 3D line preview (tublular structures)"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "fc.transform(steps + [fc.PlotAnnotation(point=fc.Point(x=50, y=50, z=15), label='zoom in to see line width remain constant')], 'plot', fc.PlotControls(style='line', line_width=2))"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### output and inspect raw data"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "plot_controls = fc.PlotControls(raw_data=True)\n",
                "plot_data = fc.transform(steps, 'plot', plot_controls)\n",
                "print('first five values of the first path:')\n",
                "print(f'    x values: {plot_data.paths[0].xvals[0:4]}')\n",
                "print(f'    y values: {plot_data.paths[0].yvals[0:4]}')\n",
                "print(f'    z values: {plot_data.paths[0].zvals[0:4]}')\n",
                "print(f'    extrusion width values: {plot_data.paths[0].widths[0:4]}')\n",
                "print(f'    extrusion height values: {plot_data.paths[0].heights[0:4]}')\n",
                "print(f'    color values [r, g, b]: {plot_data.paths[0].colors[0:4]}')\n",
                "print(f'    extruder state: {plot_data.paths[0].extruder.on}')\n",
                "print(f'second path (travel line of two points):\\n    {plot_data.paths[1]}')\n",
                "print(f'final path (vertical line of two points):\\n    {plot_data.paths[2]}')\n",
                "print(f'plot_data.annotations:\\n    {plot_data.annotations}')\n",
                "print(f'plot_data.bounding_box:\\n    {plot_data.bounding_box}')"
            ]
        },
        {
            "attachments": {},
            "cell_type": "markdown",
            "metadata": {},
            "source": [
                "#### create custom plots\n",
                "\n",
                "this is the same path as in previous plots but this plot doesn't scale xyz axes equally"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "def custom_plot(data):\n",
                "    import plotly.graph_objects as go\n",
                "    fig = go.Figure(layout=go.Layout(template='plotly_dark'))\n",
                "    for i in range(len(data.paths)):\n",
                "        line_color = 'rgb(255,160,0)' if data.paths[i].extruder.on == True else 'rgb(200,0,0)'\n",
                "        fig.add_trace(go.Scatter3d(mode='lines', x=data.paths[i].xvals, y=data.paths[i].yvals,z=data.paths[i].zvals, line=dict(color=line_color)))\n",
                "    fig.show()\n",
                "    \n",
                "plot_controls = fc.PlotControls(raw_data=True)\n",
                "plot_data = fc.transform(steps, 'plot', plot_controls)\n",
                "custom_plot(plot_data)"
            ]
        }
    ],
    "metadata": {
        "kernelspec": {
            "display_name": "fc",
            "language": "python",
            "name": "python3"
        },
        "language_info": {
            "codemirror_mode": {
                "name": "ipython",
                "version": 3
            },
            "file_extension": ".py",
            "mimetype": "text/x-python",
            "name": "python",
            "nbconvert_exporter": "python",
            "pygments_lexer": "ipython3",
            "version": "3.11.3"
        },
        "orig_nbformat": 4,
        "vscode": {
            "interpreter": {
                "hash": "2b13a99eb0d91dd901c683fa32c6210ac0c6779bab056ce7c570b3b366dfe237"
            }
        }
    },
    "nbformat": 4,
    "nbformat_minor": 2
}
